package pwd.allen.password.config;

import pwd.allen.password.CheckMsg;
import pwd.allen.password.ICheckRule;
import pwd.allen.password.PwdCheckProperties;
import pwd.allen.password.annotation.CheckParam;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * @author pwdan
 * @create 2020-10-22 23:31
 **/
//@Component
@Aspect
public class WeakPwdCheckAspect {

    private static final Logger logger = LoggerFactory.getLogger(WeakPwdCheckAspect.class);

    @Autowired
    private ICheckRule checkRule;

    @Autowired
    private PwdCheckProperties properties;

    @Pointcut(value = "@annotation(pwd.allen.password.annotation.WeakPwdCheck)")
    public void weakPwdCheck() {}
    /**
     * 拦截并处理@WeakPwdCheck注释的方法
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("weakPwdCheck()")
    public Object exec4WeakPwdCheck(ProceedingJoinPoint joinPoint) throws Throwable {
        // 弱密码校验是否开启
        if (!properties.isEnabled()) {
            return joinPoint.proceed();
        }

        CheckMsg checkMsg = null;
        CheckParam annotation = null;
        String password = null;

        //<editor-fold desc="获取密码及注解">
        Signature signature = joinPoint.getSignature();
        Method method = MethodSignature.class.cast(signature).getMethod();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Annotation[][] pa = method.getParameterAnnotations();
        for (int i = 0; i < parameterTypes.length; i++) {
            for (Annotation anno : pa[i]) {
                if (anno instanceof CheckParam) {
                    annotation = (CheckParam) anno;
                    password = (String) joinPoint.getArgs()[i];
                    break;
                }
            }
            if (annotation != null) {
                break;
            }
        }
        //</editor-fold>

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null || !(requestAttributes instanceof ServletRequestAttributes)) {
            throw new RuntimeException("servletRequestAttributes获取异常！");
        }
        ServletRequestAttributes servletRequestAttributes = ServletRequestAttributes.class.cast(requestAttributes);
        HttpServletResponse resp = servletRequestAttributes.getResponse();
        HttpServletRequest req = servletRequestAttributes.getRequest();
        if (resp == null) {
            throw new RuntimeException("response获取异常！");
        }

        if (annotation == null) {
            checkMsg = new CheckMsg(CheckMsg.Type.ERROR, "弱密码校验方法需要指定密码!");
        }
        if (checkMsg == null) {
            //<editor-fold desc="解析密码">
            if (!StringUtils.isEmpty(annotation.method4Parse())) {
                try {
                    Method method4Parse = signature.getDeclaringType().getDeclaredMethod(annotation.method4Parse(), String.class);
                    password = (String) method4Parse.invoke(joinPoint.getTarget(), password);
                    logger.debug("解析密码结果为：{}", password);
                } catch (NoSuchMethodException e) {
                    checkMsg = new CheckMsg(CheckMsg.Type.ERROR, "method4Parse指定的方法不存在!");
                } catch (Exception e) {
                    logger.error(e.toString(), e);
                    checkMsg = new CheckMsg(CheckMsg.Type.ERROR, e.toString());
                }
            }
            //</editor-fold>
        }
        if (checkMsg == null) {
            // 使用弱密码工具进行校验
            checkMsg = checkRule.check(password);
        }
        if (checkMsg == null) {
            checkMsg = new CheckMsg(CheckMsg.Type.NOPASS, "校验结果为空!");
        }
        logger.debug("密码【{}】校验结果为：{}", password, checkMsg);
        if (checkMsg.getType() != CheckMsg.Type.PASS) {
            //<editor-fold desc="验证未通过的处理逻辑">
            if (annotation != null && !StringUtils.isEmpty(annotation.urlForward())) {
                // 转发
                req.setAttribute("checkMsg", checkMsg);
                req.getRequestDispatcher(annotation.urlForward().trim()).forward(req, resp);
            } else if (annotation != null && !StringUtils.isEmpty(annotation.urlRedirect())) {
                // 重定向
                resp.sendRedirect(annotation.urlRedirect());
            } else {
                // 直接返回json错误信息
                resp.setContentType("application/json; charset=utf-8");
                PrintWriter writer = resp.getWriter();
                ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
                writer.write(objectMapper.writeValueAsString(checkMsg));
                resp.flushBuffer();
            }
            //</editor-fold>
            return null;
        }

        return joinPoint.proceed();
    }
}
